import React, {
  useMemo,
  useState,
  useEffect,
  useRef,
  useImperativeHandle, LegacyRef
} from 'react';
import {View, ScrollView, Text, Block} from '@tarojs/components';
import {AtIcon} from 'taro-ui';
import './index.scss';
// import NoData from '../no-data';
import {useVirtualList, VirtualListParams} from './hook';


/**
 * 对象浅比较
 * @param {object} a
 * @param {object} b
 * @returns
 */
export function shallowEqual(a?: object, b?: object) {
  if (a === b) return true;

  if (a === undefined || b === undefined) {
    return false
  }

  let keysA = Object.keys(a);
  let keysB = Object.keys(b);
  if (keysA.length !== keysB.length) return false;
  let hasDiff = keysA.some(key => a[key] !== b[key]);
  return !hasDiff;
}


export interface ItemT {
}

export interface FlowListProps extends Omit<VirtualListParams, 'pageNo' | 'data'> {
  api?: (params: { [key: string]: any }) => Promise<PageList<ItemT>>; //接口
  apiData?: { [key: string]: any };
  initData?: ItemT[];
  onFetchedData?: (data: ItemT[], res: PageList<ItemT>) => void | ItemT[]; //拉取数据
  scrollStyle?: React.CSSProperties;
  addrenderItem?: () => React.ReactElement<any>;
  onScroll?: (e: any) => void; //滑动监听
  onScrollClick?: (e: any) => void; //ScrollView点击
  scrollY?: boolean; //滑动方向
  isScrollToTop?: boolean;
  onRefresherPulling?: () => void; //自定义下拉刷新控件被下拉
  onRefresherRestore?: () => void; //自定义下拉刷新被复位
  onScrollToUpper?: () => void; //滚动到顶部/左边
  onScrollToLower?: () => void;
  onRefresherRefreshFun?: () => void; //自定义下拉刷新被触发
  renderItem: (item: any, index: number, mainIndex: number) => React.ReactElement<any>;
  renderListHeaderComponent?: () => React.ReactElement<any>; //自定义头部
  refresherBackground?: string;
  noMoreDataStyle?: React.CSSProperties;
  hasPopData?: boolean;
  popDataFunc?: (data: ItemT[]) => void;
  renderListEmptyComponent?: () => React.ReactElement<any>; //自定义空页面
  renderLoadingComponent?: () => React.ReactElement<any>; //自定义Loading
  contentClassName?: string;
  pageSize?: number;
  scrollTop?: number;
  ref?: LegacyRef<FlowListComponentHandle>,
}

export interface FlowListComponentHandle {
  refresh(): void;

  getData(): any;

  setData(res: ItemT[]): void;
}


export interface PageList<T> {
  count?: string; //数据总条数，前端接口可忽略改字段
  entities?: T[]; //数据集合
  pageNo?: number; //当前页码
  pageSize?: number; //每页条数
}

/**
 * virtual-flow-list 列表展示组件
 */
const FlowList: React.ForwardRefRenderFunction<FlowListComponentHandle,
  FlowListProps> = (
  {
    api,
    apiData,
    initData,
    scrollStyle,
    onScroll,
    onScrollClick,
    scrollY = true,
    onScrollToUpper,
    onRefresherPulling,
    onRefresherRestore,
    onRefresherRefreshFun,
    onFetchedData,
    renderItem,
    renderListHeaderComponent,
    renderListEmptyComponent,
    renderLoadingComponent,
    refresherBackground,
    noMoreDataStyle,
    isScrollToTop = false,
    hasPopData = false,
    contentClassName,
    popDataFunc,
    scrollTop,
    segmentNum = 20,
    screenNum = 2,
    listId = "zt-virtial-list",
    scrollViewProps
  }: FlowListProps,
  ref
) => {
  const [data, setData] = useState<any[]>(() => {
    return initData ? initData : [];
  });
  const [refreshing, setRefreshing] = useState(false);
  const [noMoreData, setNoMoreData] = useState(false);
  const [hasLoadData, setHasLoadData] = useState(false);
  const [apiProps, setApiProps] = useState(apiData);
  const [scrollIntoView, setScrollIntoView] = useState('');
  const pageNo = useRef(1);
  const loading = useRef(false);

  const [twoList] = useVirtualList({
    data,
    screenNum,
    listId,
    scrollViewProps,
    segmentNum,
    pageNo: pageNo.current
  })


  useEffect(() => {
    if (isScrollToTop) {
      setScrollIntoView('scrollDivTop');
    } else {
      setScrollIntoView('');
    }
  }, [isScrollToTop]);

  const handleScroll = e => {
    let top = e.detail.scrollTop;
    if (top < 30) {
      setScrollIntoView('');
    }
    onScroll && onScroll(e);
  };

  useImperativeHandle(ref, () => {
    return {
      refresh() {
        onRefresherRefresh();
      },
      getData() {
        return data;
      },
      setData(res) {
        setData(res);
      }
    };
  });

  useEffect(() => {
    fetchData(true);
  }, [apiProps]);

  useEffect(() => {
    if (!shallowEqual(apiData, apiProps)) {
      setApiProps(apiData);
    }
  }, [apiData, apiProps]);

  const fetchData = async (refresh: boolean | void): Promise<void> => {
    if (pageNo.current > 1) {
      if (loading.current) return;
      loading.current = true;
    }
    if (refresh) {
      pageNo.current = 1;
    }
    let params = {pageNo: pageNo.current, pageSize: 20, ...apiData};
    try {
      // let res = api && (await api(params));
      /********** 测试数据 *************/
      const arr: number[] = [];
      Array(20)
        .fill(0)
        .forEach((item, index) => {
          arr.push(data.length + index);
        });

      const res = {
        entities: arr
      };

      if (!res) {
        loading.current = false;
        setRefreshing(false);
        if (!refresh) {
          setNoMoreData(true);
        } else {
          setHasLoadData(true);
        }
      } else {
        res && afterFetchData(res);
        loading.current = false;
      }
    } catch (res) {
      loading.current = false;
      setRefreshing(false);
      setHasLoadData(true);
      if (!refresh) {
        setNoMoreData(true);
      }
    }
  };

  const afterFetchData = (res: PageList<ItemT>) => {
    let resEntities = res && res.entities;
    let fetchData =
      resEntities && onFetchedData
        ? onFetchedData(res.entities || [], res)
        : null;
    let entities = fetchData || resEntities || [];
    let extData: any[] = [];
    if (pageNo.current === 1) {
      extData = [...entities];
      setNoMoreData(false);
    } else {
      extData = [...data, ...entities];
    }
    //  后台返回的数据有可能会少于pageSize但还有下一页数据
    if (entities.length < 20) {
      setNoMoreData(true);
    } else {
      pageNo.current++;
    }
    setData(extData);
    setHasLoadData(true);
    if (hasPopData) {
      popDataFunc && popDataFunc(extData);
    }
    setRefreshing(false);
  };

  const handleLoadMore = () => {
    if (loading.current || noMoreData) {
      return;
    }
    fetchData(false);
  };

  const onRefresherRefresh = () => {
    onRefresherRefreshFun && onRefresherRefreshFun();
    setRefreshing(true);
    fetchData(true);
  };

  const renderLoadingComponentDefault = () => {
    return (
      <View className="loading-wrap">
        <AtIcon
          className="loading-icon"
          value="loading-3"
          size="32"
          color="#aaa"
        ></AtIcon>
        <Text className="loading-text">加载中…</Text>
      </View>
    );
  };

  const renderListFooterComponent = () => {
    if (!hasLoadData) {
      return renderLoadingComponent
        ? renderLoadingComponent()
        : renderLoadingComponentDefault();
    }
    if (!data.length) return null;
    return (
      <View className="no-more" style={noMoreDataStyle}>
        {noMoreData ? '没有更多了' : '内容加载中...'}
      </View>
    );
  };

  const renderRowItem = () => {
    if (twoList.length > 0) {
      return twoList?.map((item, pageIndex) => {
        return (
          <View key={pageIndex} className={`zt-wrap-item wrap_${pageIndex}`}>
            {
              item?.length > 0 ? (
                <Block>
                  {
                    item.map((el, index) => {
                      return renderItem?.(el, (pageIndex * segmentNum + index), pageIndex)
                    })
                  }
                </Block>
              ) : (
                <View style={{'height': `${item?.height}px`}}></View>
              )
            }
          </View>
        )
      })
    } else if (twoList.length == 0 && hasLoadData) {
      if (renderListEmptyComponent) {
        return renderListEmptyComponent();
      } else {
        return (
          <View>暂无数据</View>
          // <NoData
          //   className="message-noData"
          //   preset="no-data"
          //   content="暂无数据"
          // />
        );
      }
    } else {
      return null;
    }
  };

  const renderHeader = useMemo(() => {
    return renderListHeaderComponent && renderListHeaderComponent();
  }, [renderListHeaderComponent]);

  return (
    <View className="flow-list-wrap">
      <ScrollView
        className="scrollview"
        id={listId}
        scrollWithAnimation
        style={scrollStyle}
        scrollY={scrollY}
        refresherEnabled={true}
        refresherTriggered={refreshing}
        refresherBackground={refresherBackground}
        onRefresherRefresh={onRefresherRefresh}
        scrollIntoView={scrollIntoView}
        scrollTop={scrollTop}
        onRefresherPulling={onRefresherPulling}
        onRefresherRestore={onRefresherRestore}
        onScrollToUpper={onScrollToUpper}
        lowerThreshold={200}
        onScroll={handleScroll}
        onScrollToLower={handleLoadMore}
        onClick={e => onScrollClick && onScrollClick(e)}
        {...scrollViewProps}
      >
        <View id="scrollDivTop"></View>
        {renderHeader}
        <View className={`list-guest list-guest-common ${contentClassName}`}>
          {renderRowItem()}
        </View>
        {renderListFooterComponent()}
      </ScrollView>
    </View>
  );
};
export default React.forwardRef(FlowList);
